package ace.tool.generate.code.impl.generator.graphql;

import ace.tool.generate.code.impl.generator.graphql.model.GraphqlTemplateModel;
import ace.tool.generate.code.impl.generator.graphql.model.GraphqlTemplateModelField;
import ace.tool.generate.code.impl.resolver.TemplateModelClassResolver;
import ace.tool.generate.code.impl.resolver.impl.TemplateModelDataJdbcClassResolverImpl;
import ace.tool.generate.code.impl.resolver.model.TemplateModel;
import ace.tool.generate.code.impl.resolver.model.TemplateModelField;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.data.annotation.Id;

/**
 * @author caspar
 * @date 2023/11/17 9:57 spring data jdbc entity 生成graphql 相关文件
 */
public class GraphqlTemplateModelResolver {
  private static final Map<Class, String> DEFAULT_TYPE_MAP;
  private final Map<Class, String> typeMap;
  private final String defaultType;

  static {
    DEFAULT_TYPE_MAP = new HashMap<>();
    DEFAULT_TYPE_MAP.put(Integer.class, "Int");
    DEFAULT_TYPE_MAP.put(Long.class, "Long");
    DEFAULT_TYPE_MAP.put(String.class, "String");
    DEFAULT_TYPE_MAP.put(BigDecimal.class, "BigDecimal");
    DEFAULT_TYPE_MAP.put(Id.class, "ID");
    DEFAULT_TYPE_MAP.put(Boolean.class, "Boolean");
    DEFAULT_TYPE_MAP.put(Date.class, "Date");
    DEFAULT_TYPE_MAP.put(LocalDateTime.class, "DateTime");
    DEFAULT_TYPE_MAP.put(UUID.class, "UUID");
    DEFAULT_TYPE_MAP.put(Short.class, "Short");
    DEFAULT_TYPE_MAP.put(BigInteger.class, "BigInteger");
  }

  private final TemplateModelClassResolver resolver;
  private static final TemplateModelClassResolver defaultResolver =
      new TemplateModelDataJdbcClassResolverImpl();

  public GraphqlTemplateModelResolver() {
    this.resolver = defaultResolver;
    this.typeMap = DEFAULT_TYPE_MAP;
    this.defaultType = "Object";
  }

  public GraphqlTemplateModel resolveModel(Class cls) {
    TemplateModel templateModel = resolver.resolve(cls);
    List<GraphqlTemplateModelField> fields =
        Stream.ofNullable(templateModel.getFields())
            .flatMap(List::stream)
            .map(this::resolveModelField)
            .collect(Collectors.toList());
    GraphqlTemplateModel model =
        GraphqlTemplateModel.builder()
            .name(templateModel.getName())
            .remark(templateModel.getRemark())
            .fields(fields)
            .build();
    return model;
  }

  private GraphqlTemplateModelField resolveModelField(TemplateModelField templateModelField) {

    return GraphqlTemplateModelField.builder()
        .name(templateModelField.getName())
        .type(this.typeMap.getOrDefault(templateModelField.getType(), defaultType))
        .remark(templateModelField.getRemark())
        .idFlag(templateModelField.getIdFlag())
        .build();
  }
}
